front_page.png

Contents¶

  • Flight Logs
  • 3D Geometry
  • State Representation
  • Model and Environment
  • Telemetry

Flight Logs¶

  • Generally nasty binary formats
  • pymavlink provides a parser for Ardupilot Logs
  • pip install flightdata
  • Parses and handles flight data with a standard interface and units
  • Dumps to csv for faster reading in future
In [3]:
from flightdata import Flight
fl = Flight.from_csv("montserrat.csv")
fl.data
Out[3]:
time_index servos_6 servos_7 axis_rate_roll tx_controls_3 servos_1 tx_controls_4 servos_4 magnetometer_0 time_actual ... quaternion_1 rpm_0 battery_1 altitude_baro current_1 altitude_gps quaternion_3 rpm_1 quaternion_0 quaternion_2
time_index
0.000000 0.000000 NaN NaN NaN NaN NaN NaN NaN NaN 230.034444 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
0.039956 0.039956 1000.0 1500.0 0.001441 1498.0 1431.0 987.0 1472.0 -324.0 230.074400 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
0.079985 0.079985 1000.0 1500.0 0.003569 1498.0 1431.0 987.0 1472.0 -324.0 230.114429 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
0.120053 0.120053 1000.0 1500.0 0.009420 1498.0 1431.0 987.0 1472.0 -324.0 230.154497 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
0.159986 0.159986 1000.0 1500.0 0.006934 1498.0 1431.0 987.0 1472.0 -319.0 230.194430 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1539.599988 1539.599988 1000.0 1500.0 0.010239 1500.0 1428.0 987.0 1472.0 -258.0 1769.634432 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1539.640014 1539.640014 1000.0 1500.0 -0.000365 1500.0 1428.0 987.0 1472.0 -269.0 1769.674458 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1539.680044 1539.680044 1000.0 1500.0 -0.002612 1498.0 1428.0 987.0 1472.0 -269.0 1769.714488 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1539.719949 1539.719949 1000.0 1500.0 0.003439 1500.0 1428.0 987.0 1472.0 -269.0 1769.754393 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
1539.759993 1539.759993 1000.0 1500.0 0.001994 1498.0 1429.0 987.0 1472.0 -270.0 1769.794437 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN

38495 rows × 69 columns

In [4]:
fl.global_position
Out[4]:
global_position_latitude global_position_longitude
time_index
0.000000 NaN NaN
0.039956 NaN NaN
0.079985 16.714695 -62.227804
0.120053 16.714695 -62.227804
0.159986 16.714695 -62.227804
... ... ...
1539.599988 16.714697 -62.227885
1539.640014 16.714697 -62.227885
1539.680044 16.714697 -62.227885
1539.719949 16.714697 -62.227885
1539.759993 16.714697 -62.227885

38495 rows × 2 columns

In [5]:
fl.servos
Out[5]:
servos_0 servos_1 servos_2 servos_3 servos_4 servos_5 servos_6 servos_7 servos_8 servos_9 servos_10 servos_11 servos_12 servos_13
time_index
0.000000 NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
0.039956 1517.0 1431.0 1000.0 1565.0 1472.0 0.0 1000.0 1500.0 1861.0 1160.0 0.0 0.0 0.0 0.0
0.079985 1517.0 1431.0 1000.0 1565.0 1472.0 0.0 1000.0 1500.0 1861.0 1160.0 0.0 0.0 0.0 0.0
0.120053 1517.0 1431.0 1000.0 1565.0 1472.0 0.0 1000.0 1500.0 1861.0 1160.0 0.0 0.0 0.0 0.0
0.159986 1517.0 1431.0 1000.0 1565.0 1472.0 0.0 1000.0 1500.0 1861.0 1160.0 0.0 0.0 0.0 0.0
... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1539.599988 1517.0 1428.0 1000.0 1565.0 1472.0 0.0 1000.0 1500.0 2031.0 956.0 0.0 0.0 0.0 0.0
1539.640014 1517.0 1428.0 1000.0 1565.0 1472.0 0.0 1000.0 1500.0 2031.0 956.0 0.0 0.0 0.0 0.0
1539.680044 1517.0 1428.0 1000.0 1565.0 1472.0 0.0 1000.0 1500.0 2031.0 956.0 0.0 0.0 0.0 0.0
1539.719949 1517.0 1428.0 1000.0 1565.0 1472.0 0.0 1000.0 1500.0 2031.0 956.0 0.0 0.0 0.0 0.0
1539.759993 1517.0 1429.0 1000.0 1565.0 1472.0 0.0 1000.0 1500.0 2031.0 956.0 0.0 0.0 0.0 0.0

38495 rows × 14 columns

In [6]:
px.scatter_geo(lat=fl.global_position.iloc[:,0], lon=fl.global_position.iloc[:,1])

3D Geometry¶

  • pip install pfc-geometry
  • Nice interface to geometric entities
  • Based on numpy
  • Objects to handle arrays of Point, Quaternion, GPS, Coord, Transformation
  • Extensive use of magic methods
  • built on 2D numpy arrays
In [7]:
from geometry import *
Point(1,2,3).data
Out[7]:
array([[1, 2, 3]])

Basic Geometry Constructors and Operations¶

In [8]:
plotpoints(2,  
    constructors = [
        Point(1, 2, 0), PX(5), P0(),
        Point(np.random.random((100,3))*-5 -5),
    ],
    operations = [
        Point(1,1,0) * np.linspace(0,10,10),
        PX(1) * np.linspace(0,5,4) * 2,
        PX(-1,10).cumsum()
    ]
)

More Geometric Operations¶

In [9]:
from flightplotting import *
origin = Coord.zero()
transformed = Transformation(Point(10,10,10), Euldeg(45, 45, 45)).apply(origin)
create_3d_plot(axestrace([origin,  transformed], 5))

State Representation¶

  • Handles time, Position, Attitude and their derivatives
  • wraps a pandas dataframe
  • Made up of groups of geometric entities
  • Constructored from flight data or from scratch
  • pip install flightanalysis
In [10]:
from flightanalysis import *
st = State.from_flight(fl[fl.imu_ready_time():])
st.data
Out[10]:
t dt x y z rw rx ry rz u ... w p q r du dv dw dp dq dr
0.000000 1.684872e+09 0.040068 -2.531698 -1.774133 -12.398801 0.006849 0.707074 0.707100 -0.003147 -0.006290 ... -0.046262 0.003569 -0.005179 -0.030917 0.490665 0.652766 -9.562064 0.146012 0.124210 0.115515
0.040068 1.684872e+09 0.040001 -2.532421 -1.774749 -12.402140 0.006849 0.707074 0.707100 -0.003147 -0.006619 ... -0.046038 0.009420 -0.000202 -0.026289 0.355979 0.597122 -9.423726 0.042064 0.051102 -0.002953
0.080001 1.684872e+09 0.039993 -2.533040 -1.775352 -12.404810 0.006788 0.707074 0.707100 -0.003209 -0.007012 ... -0.045611 0.006934 -0.001090 -0.031154 0.443138 0.579210 -9.312488 -0.056727 -0.057763 -0.050796
0.120054 1.684872e+09 0.039983 -2.533577 -1.775947 -12.406843 0.006726 0.707075 0.707099 -0.003270 -0.007376 ... -0.045472 0.004882 -0.004822 -0.030352 0.447935 0.565713 -9.385395 -0.113635 -0.074322 0.003750
0.159967 1.684872e+09 0.039979 -2.534048 -1.776527 -12.408628 0.006726 0.707075 0.707099 -0.003270 -0.007756 ... -0.045771 -0.002153 -0.007034 -0.030854 0.434582 0.589533 -9.457307 -0.076899 0.058784 -0.003136
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1539.520003 1.684873e+09 0.040032 4.086720 -7.192983 -7.675329 -0.026632 0.761554 0.644811 -0.059542 0.055480 ... 0.084307 0.010239 -0.000310 -0.011462 0.320623 -0.616758 -9.750603 -0.030198 0.011543 0.084326
1539.560029 1.684873e+09 0.040028 4.086779 -7.192683 -7.677584 -0.026632 0.761554 0.644811 -0.059542 0.056572 ... 0.084107 -0.000365 0.000066 -0.003348 0.281426 -0.544395 -9.751322 -0.160521 -0.030017 -0.002480
1539.600059 1.684873e+09 0.039968 4.086976 -7.192109 -7.680097 -0.026632 0.761554 0.644811 -0.059542 0.056988 ... 0.085211 -0.002612 -0.002713 -0.011661 0.309695 -0.487353 -9.747066 0.047594 0.017272 -0.045476
1539.639964 1.684873e+09 0.039974 4.087298 -7.191294 -7.683197 -0.026632 0.761554 0.644811 -0.059542 0.058266 ... 0.085886 0.003439 0.001446 -0.006983 0.278705 -0.579164 -9.771101 0.057608 0.009559 0.031185
1539.680008 1.684873e+09 0.040044 4.087129 -7.192113 -7.684982 -0.026632 0.761554 0.644811 -0.059542 0.057955 ... 0.086363 0.001994 -0.001949 -0.009168 0.310242 -0.579635 -9.474611 -0.036103 -0.084786 -0.054542

38493 rows × 21 columns

In [11]:
pd.DataFrame([[k, v.obj.__name__, v.keys] for k, v in State.constructs.data.items()], columns=['name', 'object', 'cols'])
Out[11]:
name object cols
0 time Time [t, dt]
1 pos Point [x, y, z]
2 att Quaternion [rw, rx, ry, rz]
3 vel Point [u, v, w]
4 rvel Point [p, q, r]
5 acc Point [du, dv, dw]
6 racc Point [dp, dq, dr]
In [12]:
st.time
Out[12]:
Time(t_=1684872557.28 dt_=0.04, len=38493)
In [13]:
st.pos
Out[13]:
Point(x_=-1503.97 y_=1680.0 z_=436.41, len=38493)
In [14]:
st.att
Out[14]:
Quaternion(w_=-0.04 x_=0.41 y_=0.63 z_=-0.04, len=38493)
In [15]:
plotsec(st)
In [16]:
plotsec(st[135:142], nmodels=20, scale=2)

Generating Trajectories¶

In [17]:
track = State.from_transform(
    Transformation(P0(), Euldeg(180,0,0)), 
    vel=PX(20), rvel=np.pi * Point(0.25, 0.25, 0)
).extrapolate(6)

fig = plotsec(track, scale=2, nmodels=10)
fig.show()

Displaying Quantities¶

In [18]:
fig.add_traces(vectors(20, track, 0.5*track.body_to_world(track.acc, True)))
fig.add_traces(vectors(20, track, 5*track.body_to_world(track.rvel, True), line=dict(color="green")))
fig.show()

Model and Environment¶

  • Add some more State type datastructures
    • Environment
      • atmosphere
      • wind
    • Flow
      • alpha & beta
      • q
    • Coefficients
      • Forces
      • Moments
  • Define some constants
    • S (wing area), c (chord), b (span), mass (mass and inertia properties)

Add some wind and rotate to the Wind axis¶

In [19]:
env = Environment.from_constructs(Time.now(), wind=PY(5))
wind = track.track_to_wind(env)
plotsec([track, wind], nmodels=10, scale=3)

Calculate the Coefficients, Alpha and Beta¶

In [20]:
from flightanalysis.model import cold_draft as constants
flow = Flow.build(wind, env)
coeffs = Coefficients.build(wind, flow.q, constants)
flow = flow.rotate(coeffs, 10, 5) # Assume linear dcl/da and dcydb. 
px.line(np.degrees(flow.flow.to_pandas().iloc[:,:-1])).show()

Rotate by Alpha and Beta to get Body Axis¶

In [21]:
body = wind.wind_to_body(flow)
plotsec([track, wind, body], nmodels=10, scale=3)

Telemetry¶

  • Most drones communicate via MAVLink (pip install pymavlink)
  • dronekit wraps pymavlink to provide a higher level api
  • My alternative to dronekit: github.com/PyFlightCoach/DroneInterface
In [22]:
%%script false  --no-raise-error

vehicle = Vehicle.connect('tcp:127.0.0.1:5760', 1, 1, "log_tmp")

#getting a single mavlink message
vehicle.get_GlobalOrigin(5, None).position   # -> GPS

#getting a state object (combines 3 mavlink messages):
vehicle.get_state()

#subscribing to a higher rate for some messages
with vehicle.subscribe(vehicle.state.ids, 10):
    last_state() # gets the last
    next_state() # blocks till the next